package cn.edu.nju.software.zp13.core.nodeGenerator;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

import cn.edu.nju.software.zp13.core.nodeDescriptor.NodeDescriptor;
import cn.edu.nju.software.zp13.core.xmlNodeEntity.XmlNodeEntity;

/**
 * This class is to generate new node and append it a to a dom tree.
 * 
 * @author Ivan
 *
 */
public abstract class NodeGenerator {
	protected Document dom;

	public NodeGenerator(Document dom) {
		super();
		this.dom = dom;
	}

	/**
	 * update a dom tree's node.
	 * 
	 * @param node
	 *            the node to be updated.
	 * @param descriptor
	 *            provide new node's infomation.
	 */
	public abstract void updateDom(Node node, NodeDescriptor descriptor);

	/**
	 * return String content of a node(SimpleNode or AttributeNode).
	 * 
	 * @param descriptor
	 * @return
	 */
	public String getTextNodeContent(NodeDescriptor descriptor) {
		String content = null;
		Field f = descriptor.getField();
		Method m = descriptor.getMethod();
		XmlNodeEntity entity = descriptor.getEntity();
		if (m != null) {
			try {
				content = (String) m.invoke(entity);
			} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
				e.printStackTrace();
			} catch (ClassCastException e) {
				System.err.println(
						"Method " + m.getName() + " must return type String.");
				System.exit(-1);
			}
		} else {
			try {
				content = (String) f.get(entity);
			} catch (IllegalArgumentException | IllegalAccessException e) {
				e.printStackTrace();
			} catch (ClassCastException e) {
				System.err.println(
						entity.getClass().getName() + " has a field " + f.getName() + " which is not type String.");
				System.out.println("Please add a public method with annotation @TextNode whose fatherTag is " + f.getName()
						+ "'s tagName.");
				System.exit(-1);
			}
		}
		return content;
	}

	/**
	 * 
	 * @param descriptor
	 * @return
	 */
	public XmlNodeEntity getEntityContent(NodeDescriptor descriptor) {
		XmlNodeEntity entity = null;
		entity = getContent(entity, descriptor);
		return entity;
	}

	/**
	 * 
	 * @param descriptor
	 * @return
	 */
	public XmlNodeEntity[] getArrayEntitiesContent(NodeDescriptor descriptor) {
		XmlNodeEntity[] entities = null;
		entities = getContent(entities, descriptor);
		return entities;
	}

	/**
	 * get content of a node.
	 * 
	 * @param t
	 *            return type.
	 * @param descriptor
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private <T> T getContent(T t, NodeDescriptor descriptor) {
		Field f = descriptor.getField();
		try {
			t = (T) f.get(descriptor.getEntity());
		} catch (IllegalArgumentException | IllegalAccessException e) {
			e.printStackTrace();
		}
		return t;
	}
}
